package com.example.demo.ws;

import com.example.demo.common.ParametersUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import javax.annotation.PreDestroy;
import java.net.URI;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;


@Component
public class WsChatHandler extends TextWebSocketHandler {
    private List<UserBean> userList = new CopyOnWriteArrayList<>();

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        URI uri = session.getUri();
        String query = uri.getQuery();
        String userName = ParametersUtil.parseParameters(query, "userName");
        for(UserBean bean :  userList) {
            bean.getSession().sendMessage(
                    new TextMessage(String.format("[%s] : %s", userName, message.getPayload())));
        }
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        URI uri = session.getUri();
        String query = uri.getQuery();
        String userName = ParametersUtil.parseParameters(query, "userName");
        UserBean bean = new UserBean();
        bean.setSession(session);
        bean.setSessionId(session.getId());
        bean.setStatus("1");
        bean.setLoginTime(new Date());
        bean.setUserName(userName);
        if(!checkUserExisting(userName)) {
            userList.add(bean);
        }

        for(UserBean b :  userList) {
            b.getSession().sendMessage(new TextMessage("[SYSTEM] : Hello,  " + bean.getUserName()));
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        URI uri = session.getUri();
        String query = uri.getQuery();
        String userName = ParametersUtil.parseParameters(query, "userName");
        for(UserBean bean: userList) {
            if(bean.getUserName().equalsIgnoreCase(userName)) {
                userList.remove(bean);
                break;
            }
        }
    }


    /**
     * true existing; false not existing
     * @param userName
     * @return
     */
    private Boolean checkUserExisting(String userName) {
        if(userList.isEmpty()) {
            return false;
        }
        for(UserBean bean: userList) {
            if(bean.getUserName().equalsIgnoreCase(userName)) {
                return true;
            }
        }

        return false;
    }

    @PreDestroy
    public void destroy() {
        if(userList != null) {
            userList.clear();
        }
    }

    private static class UserBean {
        private String userName;
        private String sessionId;
        private WebSocketSession session;
        private Date loginTime;
        private String status;// 2, just set up, 1 active, 0 inactive

        public String getUserName() {
            return userName;
        }

        public void setUserName(String userName) {
            this.userName = userName;
        }

        public String getSessionId() {
            return sessionId;
        }

        public void setSessionId(String sessionId) {
            this.sessionId = sessionId;
        }

        public WebSocketSession getSession() {
            return session;
        }

        public void setSession(WebSocketSession session) {
            this.session = session;
        }

        public Date getLoginTime() {
            return loginTime;
        }

        public void setLoginTime(Date loginTime) {
            this.loginTime = loginTime;
        }

        public String getStatus() {
            return status;
        }

        public void setStatus(String status) {
            this.status = status;
        }
    }
}
